package run.siyuan.poi.policy;

import cn.hutool.core.util.ObjectUtil;
import com.deepoove.poi.XWPFTemplate;
import com.deepoove.poi.data.TextRenderData;
import com.deepoove.poi.exception.RenderException;
import com.deepoove.poi.plugin.table.LoopColumnTableRenderPolicy;
import com.deepoove.poi.render.compute.EnvModel;
import com.deepoove.poi.render.compute.RenderDataCompute;
import com.deepoove.poi.render.processor.DocumentProcessor;
import com.deepoove.poi.render.processor.EnvIterator;
import com.deepoove.poi.resolver.TemplateResolver;
import com.deepoove.poi.template.ElementTemplate;
import com.deepoove.poi.template.MetaTemplate;
import com.deepoove.poi.template.run.RunTemplate;
import com.deepoove.poi.util.ReflectionUtils;
import com.deepoove.poi.util.TableTools;
import org.apache.commons.lang3.reflect.FieldUtils;
import org.apache.poi.xwpf.usermodel.*;
import org.apache.xmlbeans.XmlCursor;
import org.apache.xmlbeans.XmlObject;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTRow;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTcPr;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTVMerge;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.STMerge;

import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

/**
 * @Description
 * @Author admin
 */
public class DefineMethodPolicy4 extends LoopColumnTableRenderPolicy {
    private String prefix;
    private String suffix;
    private boolean onSameLine;
    private int rowIndex;
    private String fieldName;

    private Integer templateRowStartIndex;


    public DefineMethodPolicy4() {
        this(false);
    }

    public DefineMethodPolicy4(boolean onSameLine) {
        this("[", "]", onSameLine);
    }

    public DefineMethodPolicy4(String prefix, String suffix) {
        this(prefix, suffix, false);
    }

    public DefineMethodPolicy4(String prefix, String suffix, boolean onSameLine) {
        this.prefix = prefix;
        this.suffix = suffix;
        this.onSameLine = onSameLine;
    }

    public void render(ElementTemplate eleTemplate, Object data, XWPFTemplate template) {
        if (data == null) {
            return;
        }
        RunTemplate runTemplate = (RunTemplate) eleTemplate;
        XWPFRun run = runTemplate.getRun();

        try {
            if (!TableTools.isInsideTable(run)) {
                throw new IllegalStateException("The template tag " + runTemplate.getSource() + " must be inside a table");
            } else {
                XWPFTableCell tagCell = (XWPFTableCell) ((XWPFParagraph) run.getParent()).getBody();
                XWPFTable table = tagCell.getTableRow().getTable();
                run.setText("", 0);
                int templateRowIndex = this.getTemplateRowIndex(tagCell);
                this.templateRowStartIndex = templateRowIndex;
                if (null != data && data instanceof Iterable) {
                    Iterator<?> iterator = ((Iterable) data).iterator();
                    XWPFTableRow templateRow = table.getRow(templateRowIndex);
                    TemplateResolver resolver = new TemplateResolver(template.getConfig().copy(this.prefix, this.suffix));
                    boolean firstFlag = true;
                    int index = 0;
                    boolean hasNext = iterator.hasNext();

                    while (hasNext) {
                        Object root = iterator.next();
                        hasNext = iterator.hasNext();
                        int insertPosition = templateRowIndex++;
                        table.insertNewTableRow(insertPosition);
                        this.setTableRow(table, templateRow, insertPosition);
                        XmlCursor newCursor = templateRow.getCtRow().newCursor();
                        newCursor.toPrevSibling();
                        XmlObject object = newCursor.getObject();
                        XWPFTableRow nextRow = new XWPFTableRow((CTRow) object, table);
                        if (!firstFlag) {
                            List<XWPFTableCell> tableCells = nextRow.getTableCells();
                            Iterator var21 = tableCells.iterator();

                            while (var21.hasNext()) {
                                XWPFTableCell cell = (XWPFTableCell) var21.next();
                                CTTcPr tcPr = TableTools.getTcPr(cell);
                                CTVMerge vMerge = tcPr.getVMerge();
                                if (null != vMerge && STMerge.RESTART == vMerge.getVal()) {
                                    vMerge.setVal(STMerge.CONTINUE);
                                }
                            }
                        } else {
                            firstFlag = false;
                        }

                        this.setTableRow(table, nextRow, insertPosition);
                        RenderDataCompute dataCompute = template.getConfig().getRenderDataComputeFactory().newCompute(EnvModel.of(root, EnvIterator.makeEnv(index++, hasNext)));
                        List<XWPFTableCell> cells = nextRow.getTableCells();
                        cells.forEach((cellx) -> {
                            List<MetaTemplate> templates = resolver.resolveBodyElements(cellx.getBodyElements());
                            (new DocumentProcessor(template, resolver, dataCompute)).process(templates);
                        });
                    }
                }

                table.removeRow(templateRowIndex);
                this.afterloop(table, data);
            }
        } catch (Exception var25) {
            throw new RenderException("HackLoopTable for " + eleTemplate + "error: " + var25.getMessage(), var25);
        }
    }

    private int getTemplateRowIndex(XWPFTableCell tagCell) {
        XWPFTableRow tagRow = tagCell.getTableRow();
        return this.onSameLine ? this.getRowIndex(tagRow) : this.getRowIndex(tagRow) + 1;
    }

    protected void afterloop(XWPFTable table, Object data) {
        if (ObjectUtil.isEmpty(data)) {
            return;
        }
        // 表格转换为二位数组
        int rowSize = table.getRows().size();
        int cellSize = table.getRows().get(templateRowStartIndex).getTableCells().size();
        String[][] array = new String[rowSize][cellSize];

        List<XWPFTableRow> rows = table.getRows();
        for (int i = templateRowStartIndex; i < rows.size(); i++) {
            XWPFTableRow tableRow = rows.get(templateRowStartIndex);
            // 列
            List<XWPFTableCell> tableCells = tableRow.getTableCells();
            for (int j = 0; j < tableCells.size(); j++) {
                array[i][j] = tableCells.get(j).getText();
            }
        }

        Integer mergerRowStartIndex = null;
        Integer mergerRowEndIndex = null;
        // 判断行是否存在相同元素
        for (int i = 0; i < array.length; i++) {
            // 行内元素比较
            for (int j = 0; j < array[i].length - 1; j++) {
                String var1 = array[i][j];
                for (int k = j + 1; k < array[i].length; k++) {
                    String var2 = array[i][k];
                    // 元素相等
                    if (!var1.equals(var2)) {
                        // 不相等直接结束循环，因为不需要合并
                        break;
                    }
                    // 记录下标
                    mergerRowStartIndex = j;
                    mergerRowEndIndex = k;
                }
                // 合并
                if (ObjectUtil.isNotEmpty(mergerRowStartIndex) && ObjectUtil.isNotEmpty(mergerRowEndIndex)) {
                    TableTools.mergeCellsVertically(table, i, mergerRowStartIndex, mergerRowEndIndex - mergerRowEndIndex);
                    mergerRowStartIndex = null;
                    mergerRowStartIndex = null;
                }
            }
        }


        if (null == fieldName || "".equals(fieldName)) {
            return;
        }
        List<LinkedHashMap<String, Object>> list = (List<LinkedHashMap<String, Object>>) data;
        String curr = null;
        int count = 0;//重复数量
        for (int i = 0; i < list.size(); i++) {
            LinkedHashMap<String, Object> linkedHashMap = list.get(i);
            for (String fieldName : linkedHashMap.keySet()) {
                String str = getFieldValue(list.get(i), fieldName);
                if (curr == null) {
                    curr = str;
                    count = 1;
                } else if (curr.equals(str)) {
                    ++count;
                } else {
                    mergeCellsVertically(table, rowIndex, i, count);
                    curr = str;
                    count = 1;
                }
            }
        }
        mergeCellsVertically(table, rowIndex, list, count);

//        for (int i = 0; i < list.size(); i++) {
//            String str = getFieldValue(list.get(i), fieldName);
//            if (curr == null) {
//                curr = str;
//                count = 1;
//            } else if (curr.equals(str)) {
//                ++count;
//            } else {
//                mergeCellsVertically(table, rowIndex, i, count);
//                curr = str;
//                count = 1;
//            }
//        }
//        mergeCellsVertically(table, rowIndex, list, count);

    }

    private void setTableRow(XWPFTable table, XWPFTableRow templateRow, int pos) {
        List<XWPFTableRow> rows = (List) ReflectionUtils.getValue("tableRows", table);
        rows.set(pos, templateRow);
        table.getCTTbl().setTrArray(pos, templateRow.getCtRow());
    }

    private int getRowIndex(XWPFTableRow row) {
        List<XWPFTableRow> rows = row.getTable().getRows();
        return rows.indexOf(row);
    }


    /**
     * 合并行
     *
     * @param rowIndex 列
     * @param index    重复行下标
     * @param count    重复数量
     */
    private void mergeCellsVertically(XWPFTable table, int rowIndex, int index, int count) {
        if (count > 1) {
            TableTools.mergeCellsVertically(table, rowIndex, index - count + 1, index);
        }
    }

    private void mergeCellsVertically(XWPFTable table, int rowIndex, List<LinkedHashMap<String, Object>> list, int count) {
        if (count > 1) {
            TableTools.mergeCellsVertically(table, rowIndex, list.size() - count + 1, list.size());
        }
    }

    /**
     * 获取值，判断是重复
     *
     * @param target    数据源
     * @param fieldName 字段名
     * @return 值
     */
    public String getFieldValue(Object target, String fieldName) {
        try {
            if (target instanceof Map) {
                return ((Map<?, ?>) target).get(fieldName).toString();
            }

            Object HSSFCell = FieldUtils.readField(target, fieldName, true);
            if (HSSFCell instanceof String) {
                return (String) HSSFCell;
            }
            TextRenderData textRenderData = (TextRenderData) HSSFCell;
            return textRenderData.getText();
        } catch (IllegalAccessException e) {
            throw new RuntimeException("字段类型不匹配，请检查字段类型和实体类是否一致");
        }
    }


}
